home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PsL Monthly 1993 December
/
PSL Monthly Shareware CD-ROM (December 1993).iso
/
prgmming
/
dos
/
c
/
comnumb.exe
/
COMPOUN.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-01
|
10KB
|
360 lines
/////////////////////////////////////////////////////////////////
// compoun.cpp: Compound number class implementation.
// Copyright (c) 1992 Azarona Software. All rights reserved.
// NOTE: Many of the routines here could be made inline for
// significant performance gains.
/////////////////////////////////////////////////////////////////
#include <ctype.h>
#include "compoun.h"
Compound::Compound()
// Default constructor sets number to "undefined."
// Default Rational() constructor called implicitly
: w(0)
{
// Nothing else to do
}
Compound::Compound(long n)
// Converts whole number n into compound number <n 0/1>.
: w(n), f(0)
{
// Nothing else to do
}
Compound::Compound(long n, Rational &r)
// Constructors compound number <n r>.
{
Set(n, r);
}
Compound::Compound(Compound const &c)
// Copy constructor
: w(c.w), f(c.f)
{
// Nothing else to do
}
Compound &Compound::operator=(Compound const &c)
// Overloaded assignment.
{
w = c.w; f = c.f; return *this;
}
void Compound::Simplify()
// Simplifies the compound number.
// ASSUMES fractional part is already simplified.
{
if (f.IsUndefined()) {
w = 0; // So we have <0 0/0> for undefined
}
else {
// Split f into whole number plus fraction.
long w1 = f.RemoveWholePart();
w += w1; // Add whole number from split to w.
// If whole number and fraction have different signs,
// we must force them to have same signs and simplify
// further.
if (w > 0 && f.IsNegative()) {
// We're using the formula: w + f = (w-1) + (f+1).
w--;
f++;
}
else if (w < 0 && f.IsPositive()) {
// We're using the formula: w + f = (w+1) + (f-1).
w++;
f--;
}
}
}
void Compound::Set(long n, Rational &r)
{
w = n; f = r;
Simplify();
}
void Compound::Negate()
// Take the negative of this compound number.
{
w = -w;
f.Negate();
}
void Compound::Invert()
// Divide 1 by this number, store result in this number.
// Uses formula: 1/c = 1/(w + n/d) = d/(w*d + n).
// Result is then simplified.
// If number is zero, we'll get a result of <0 0/0>.
// WARNING: Overflow is not checked!
{
Rational r(f.Denominator(), w*f.Denominator() + f.Numerator());
operator=(Compound(0, r));
}
int Compound::IsUndefined() const
{
return f.IsUndefined();
}
int Compound::IsNegative() const
{
return w < 0 || (w == 0 && f.IsNegative());
}
int Compound::IsPositive() const
{
return w > 0 || (w == 0 && f.IsPositive());
}
int Compound::IsZero() const
{
return w == 0 && f.IsZero();
}
istream &operator>>(istream &s, Compound &cn)
// Reads in a compound number. Legal syntaxes are:
// w, <n/d>, and <w n/d>. Appropriate whitespace
// is allowed. If the stream s is not in a good state upon
// return, then cn will contain <0 0/0>.
{
char c, syntax_error = 0;
long n, d;
if (s >> c) { // Read in first non-whitespace character
if (isdigit(c) || (c == '-') || (c == '+')) {
// We have a whole number. Put back character
// and then read in the whole number.
s.putback(c);
if (s >> cn.w) {
cn.f = 0; // We have zero fractional part
}
}
else if (c == '<') {
// Reading in <w n/d> or <n/d> syntax
if (s >> n) {
// Might have w or n, find out by looking for '/'
if (s >> c) {
if (c == '/') {
// Guess we have n. That means w = 0. Grab d.
cn.w = 0;
s >> d;
}
else { // We have w. Putback c, look for n/d.
cn.w = n;
s.putback(c);
if (s >> n) { // We've got numerator
if (s >> c) { // Look for '/'
if (c == '/')
s >> d;
else syntax_error = 1;
}
}
}
if (s) { // Good so far, so look for '>'
if (s >> c) {
if (c == '>') { // Good read
cn.f.Set(n, d);
cn.Simplify();
}
else syntax_error = 1;
}
}
}
}
}
else syntax_error = 1;
}
if (syntax_error) s.clear(ios::failbit);
if (!s) { // Stream failure, so result is undefined
cn.w = 0; cn.f.Set(0, 0);
}
return s;
}
ostream &operator<<(ostream &s, const Compound &c)
// Output compound number c to stream. Outputs "und"
// for <0 0/0>. If fraction part is zero, it is not shown.
{
if (c.IsUndefined()) return s << "und";
if (c.f.IsZero()) return s << c.w;
s << '<';
if (c.w != 0) s << c.w << ' ';
s << c.f.Numerator() << '/' << c.f.Denominator();
return s << '>';
}
Compound Compound::operator-() const
// Unary - operator. Computes negative of this number
// and returns a copy.
{
return Compound(-w, -f);
}
Compound Compound::operator+() const
// Unary + operator. Returns a copy of this number.
// (Thus, semantics are consistent with unary -).
{
return Compound(*this);
}
Compound &Compound::operator+=(const Compound &r)
// Adds r to this number. Stores the result in this number.
{
return operator=(*this + r);
}
Compound &Compound::operator-=(const Compound &r)
// Subtracts r from this number. Stores the result in
// this number.
{
return operator=(*this - r);
}
Compound &Compound::operator*=(const Compound &r)
// Mutliplies this number by r. Stores the result in
// this number.
{
return operator=(*this * r);
}
Compound &Compound::operator/=(const Compound &r)
// Divides this number by r. Stores the result in
// this number.
{
return operator=(*this / r);
}
Compound &Compound::operator++()
// Prefix increment operator. Safe to use
// in expressions like ++(++r).
{
return *this += 1;
}
Compound &Compound::operator--()
// Prefix decrement operator. Safe to use
// in expressions like --(--r).
{
return *this -= 1;
}
Compound Compound::operator++(int)
// Postfix increment. Note that we don't return a reference
// as we do with prefix increment. Instead a copy of the result
// is returned. Thus, expressions like (c++)++ will not return
// the correct result.
// WARNING: Result not checked for possible overflow.
{
Compound old(*this);
*this += 1;
return old;
}
Compound Compound::operator--(int)
// Postfix decrement. Note that we don't return a reference
// as we do with prefix decrement. Instead a copy of the result
// is returned. Thus, expressions like (c--)-- will not return
// the correct result.
// WARNING: Result not checked for possible overflow.
{
Compound old(*this);
*this -= 1;
return old;
}
Compound operator+(const Compound &a, const Compound &b)
// Adds a and b, returning the result. Uses the formula:
// a + b = (aw + af) + (bw + bf) = (aw + bw) + (af + bf)
// and simplifies the result.
{
return Compound(a.w + b.w, a.f + b.f);
}
Compound operator-(const Compound &a, const Compound &b)
// Subtracts b from a and returns result. Uses the
// operator+() function to do the dirty work.
// WARNING: Result not checked for possible overflow.
{
Compound nb(b);
nb.Negate();
return a + nb; // Ie: a + (-b)
}
Compound operator*(const Compound &a, const Compound &b)
// Multiplies a and b together, returning the result.
// Uses the formula: a * b = (aw + af) * (bw + bf)
// = aw*bw + af*bf + aw*bf + af*bw
// In the calculations, we keep extracting the whole part
// of the fraction terms, to keep down chances of overflow.
{
long rw = a.w * b.w;
Rational rf(a.f * b.f);
rw += rf.RemoveWholePart();
rf += a.w * b.f;
rw += rf.RemoveWholePart();
rf += a.f * b.w;
rw += rf.RemoveWholePart();
return Compound(rw, rf);
}
Compound operator/(const Compound &a, const Compound &b)
// Divides a by b, returning the result. Note that
// operator*() does all the dirty